#ifndef __MY_DATA__
#define __MY_DATA__
#include "util.hpp"
#include <mysql/mysql.h>
#include <mutex>

namespace aod
{
#define HOST "127.0.0.1"
#define USER "root"
#define PASS ""
#define NAME "aod_system"

    static MYSQL *MysqlInit() // 为什么是static
    {
        MYSQL *mysql = mysql_init(NULL);
        if (mysql == NULL)
        {
            std::cout << "init mysql instance failed" << std::endl;
            return NULL;
        }
        if (mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0, NULL, 0) == NULL) // port暂且未设置 0是特殊的？？
        {
            std::cout << "connect mysql server failed!" << std::endl;
            mysql_close(mysql);
            return NULL;
        }
        if(mysql_set_character_set(mysql, "utf8")!=0)// 执行了 但是数据库内查询 不是utf8
        std::cout << "mysql_set_character_set failed " << std::endl;
        //std::cout << mysql << std::endl;
        return mysql;
    }

    static void MysqlDestory(MYSQL *mysql)
    {
        if (mysql != NULL)
        {
            mysql_close(mysql);
        }
        return;
    }

    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    //static void MysqlQuery(MYSQL *mysql, const std::string &sql)
    // 定位到这个函数有问题 postman报错secket hang up
    // 终端报错 segmentation fault
    // 没有执行函数体 直接就报错了？？？
    {

        // std::cout << sql << std::endl;
        // try catch 调试？？
        int ret = mysql_query(mysql, sql.c_str());//段错误??.
       
        if (ret != 0)
        {
            std::cout << sql << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
            return false;
        }
         return true;
    }

    class TableVideo
    {
    private:
        MYSQL *_mysql;     // 一个对象就是一个客户端，管理一张表？？
        std::mutex _mutex; // 防备多线程中的线程安全问题
    public:
        TableVideo() // 初始化mysql句柄
        {
            _mysql = MysqlInit();
            //std::cout<< _mysql << std::endl;
            if (_mysql == NULL)
            {
                exit(-1);
            }
        }
        ~TableVideo() // 释放mysql句柄
        {
            MysqlDestory(_mysql);
        }
        bool Insert(const Json::Value &video) // 新增-传输入视频信息
        {
            // id name info video image
            std::string sql;
            sql.resize(4096 + video["info"].asString().size());    // 防止简介过长
#define INSERT_VIDEO "insert tb_video values (null,'%s','%s','%s','%s');" //!!??
            if (video["name"].asString().size() == 0)
            {
                return false;
            }
            // 要完成的细致的话需要对各个数据进行校验，因为不校验直接用有可能出现问题
            sprintf(&sql[0], INSERT_VIDEO,  video["name"].asCString(),
                    video["info"].asCString(),
                    video["video"].asCString(),
                    video["image"].asCString());
            //         //有错误 查找！！
            //         //难道是这个有越界行为吗？ no！
            //return true;
            return MysqlQuery(_mysql, sql);//调用此接口 报段错误 
            //MysqlQuery(_mysql, sql);//调用此接口 报段错误 
            //return true;

        }

        bool Update(int video_id, const Json::Value &video) // 修改-输入视频id，和信息
        {
            std::string sql;
            sql.resize(4096 + video["info"].asString().size()); // 防止简介过长
#define UPDATE_VIDEO "update tb_video set name = '%s',info = '%s' where id = %d;"
            sprintf(&sql[0], UPDATE_VIDEO,
                    video["name"].asCString(),
                    video["info"].asCString(),
                    video_id);
           return MysqlQuery(_mysql, sql);
            //MysqlQuery(_mysql, sql);
            //return true;

        }

        bool Delete(int video_id) // 删除-输入入视频id
        {
#define DELETE_VIDEO "delete from tb_video where id = %d ;"
            char sql[1024] ={0};
            sprintf(sql, DELETE_VIDEO, video_id);
            return MysqlQuery(_mysql,sql);
             ///MysqlQuery(_mysql,sql);
             //return true;

        }

        bool SelectAll(Json::Value *videos) // 查询所有--输出所有视频信息
        {
#define SELECTALL_VIDEO "select * from tb_video;"
            _mutex.lock(); //---lock start 保护查询与保存结果到本地的过程
            //std::cout << "test" <<std::endl;
            //MysqlQuery(_mysql, SELECTALL_VIDEO);
            bool ret = MysqlQuery(_mysql, SELECTALL_VIDEO);
            if (ret == false)
            {
                _mutex.unlock(); // 避免死锁？？
                return false;
            }
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); //----lock end
            int num_rows = mysql_num_rows(res);
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]); // 字符串---数字
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            mysql_free_result(res);
            return true;       
        }

        bool SelectOne(int video_id, Json::Value *video) // 查询单个-输入视频id，输出对应的视频信息
        {
#define SELECTONE_VIDEO "select * from tb_video where id = '%d';"
            char sql[1024] = {0};
            sprintf(sql, SELECTONE_VIDEO, video_id);
            _mutex.lock(); //---lock start 保护查询与保存结果到本地的过程
           // MysqlQuery(_mysql, sql);
            bool ret = MysqlQuery(_mysql, sql);
            if (ret == false)
            {
                _mutex.unlock(); // 避免死锁？？
                return false;
            }
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); //----lock end
            int num_rows = mysql_num_rows(res);
            if (num_rows != 1)
            {
                std::cout << "have no data!" << std::endl;
                mysql_free_result(res);
            }
            MYSQL_ROW row = mysql_fetch_row(res);
            (*video)["id"] = atoi(row[0]); // 字符串---数字
            (*video)["name"] = row[1];
            (*video)["info"] = row[2];
            (*video)["video"] = row[3];
            (*video)["image"] = row[4];
            mysql_free_result(res);
            return true;
        }

        bool SelectLike(const std::string &key,Json::Value *videos) // 模糊匹配-输入名称关键字，输出视频信息
        {
            #define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%';" //
            char sql[1024] = {0};
            sprintf(sql, SELECTLIKE_VIDEO, key.c_str());
            _mutex.lock(); //---lock start 保护查询与保存结果到本地的过程
            
             //MysqlQuery(_mysql, sql);
            bool ret = MysqlQuery(_mysql, sql);
            if (ret == false)
            {
                _mutex.unlock(); // 避免死锁？？
                return false;
            }
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); //----lock end
            int num_rows = mysql_num_rows(res);
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]); // 字符串---数字
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            mysql_free_result(res);
            return true;
        }
    };

}
#endif